package com.lineage.server.world;

import com.lineage.server.model.Instance.L1MonsterInstance;
import com.lineage.server.model.L1Location;
import com.lineage.server.model.L1Object;
import com.lineage.server.model.map.L1Map;
import com.lineage.server.types.Point;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.concurrent.ConcurrentHashMap;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

public class WorldMob {
  private static final Log _log = LogFactory.getLog(WorldMob.class);
  
  private static WorldMob _instance;
  
  private final ConcurrentHashMap<Integer, L1MonsterInstance> _isMob;
  
  private Collection<L1MonsterInstance> _allMobValues;
  
  public static WorldMob get() {
    if (_instance == null)
      _instance = new WorldMob(); 
    return _instance;
  }
  
  private WorldMob() {
    this._isMob = new ConcurrentHashMap<>();
  }
  
  public Collection<L1MonsterInstance> all() {
    try {
      Collection<L1MonsterInstance> vs = this._allMobValues;
      return (vs != null) ? vs : (this._allMobValues = Collections.unmodifiableCollection(this._isMob.values()));
    } catch (Exception e) {
      _log.error(e.getLocalizedMessage(), e);
      return null;
    } 
  }
  
  public ConcurrentHashMap<Integer, L1MonsterInstance> map() {
    return this._isMob;
  }
  
  public void put(Integer key, L1MonsterInstance value) {
    try {
      this._isMob.put(key, value);
    } catch (Exception e) {
      _log.error(e.getLocalizedMessage(), e);
    } 
  }
  
  public void remove(Integer key) {
    try {
      this._isMob.remove(key);
    } catch (Exception e) {
      _log.error(e.getLocalizedMessage(), e);
    } 
  }
  
  public ArrayList<L1MonsterInstance> getVisibleMob(L1MonsterInstance src) {
    L1Map map = src.getMap();
    L1Location l1Location = src.getLocation();
    ArrayList<L1MonsterInstance> result = new ArrayList<>();
    Iterator<L1MonsterInstance> iter = all().iterator();
    while (iter.hasNext()) {
      L1MonsterInstance element = iter.next();
      if (element.equals(src))
        continue; 
      if (map != element.getMap())
        continue; 
      if (!l1Location.isInScreen((Point)element.getLocation()))
        continue; 
      result.add(element);
    } 
    return result;
  }
  
  public ArrayList<L1MonsterInstance> getVisibleMob(L1Object src) {
    L1Map map = src.getMap();
    L1Location l1Location = src.getLocation();
    ArrayList<L1MonsterInstance> result = new ArrayList<>();
    Iterator<?> iter = all().iterator();
    while (iter.hasNext()) {
      L1MonsterInstance element = (L1MonsterInstance)iter.next();
      if (!element.equals(src) && map == element.getMap() && src.get_showId() == element.get_showId() && 
        l1Location.isInScreen((Point)element.getLocation()))
        result.add(element); 
    } 
    return result;
  }
  
  public int getVisibleCount(L1MonsterInstance src) {
    L1Map map = src.getMap();
    L1Location l1Location = src.getLocation();
    int count = 0;
    Iterator<L1MonsterInstance> iter = all().iterator();
    while (iter.hasNext()) {
      L1MonsterInstance element = iter.next();
      if (element.equals(src))
        continue; 
      if (map != element.getMap())
        continue; 
      if (!l1Location.isInScreen((Point)element.getLocation()) || src.getNpcId() != element.getNpcId())
        continue; 
      count++;
    } 
    return count;
  }
  
  public int getCount(int map_id, int npc_id) {
    int count = 0;
    Iterator<L1MonsterInstance> iter = all().iterator();
    while (iter.hasNext()) {
      L1MonsterInstance element = iter.next();
      if (map_id == element.getMap().getId() && npc_id == element.getNpcId() && !element.isDead())
        count++; 
    } 
    return count;
  }
  
  public Collection<L1MonsterInstance> getAllMonster() {
    Collection<L1MonsterInstance> vs = this._allMobValues;
    return this._allMobValues = Collections.unmodifiableCollection(this._isMob.values());
  }
}
